package com.fengye.security.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fengye.security.utils.Constants;
import lombok.*;
import org.hibernate.Hibernate;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author fengyexjtu@126.com
 * @date 2022年04月13日 11:02 AM
 */

@With
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "mooc_users")
@Entity
public class User implements UserDetails, Serializable {
    @Getter
    @Setter
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Getter
    @Setter
    @Column(name = "username", length = 50, unique = true, nullable = false)
    private String username;

    @Getter
    @Setter
    @JsonIgnore
    @Column(name = "password_hash", length = 200, unique = true, nullable = false)
    private String password;

    @Getter
    @Setter
    @Column(name = "email", length = 80, unique = true, nullable = false)
    private String email;

    /**
     * 手机号
     */
    @Getter
    @Setter
    @NotNull
    @Pattern(regexp = Constants.PATTERN_MOBILE)
    @Size(min = 11, max = 11)
    @Column(length = 11, unique = true, nullable = false)
    private String mobile;

    @Getter
    @Setter
    @Column(name = "name", length = 50)
    private String name;

    @Getter
    @Setter
    @Column(name = "account_non_expired", nullable = false)
    private boolean accountNonExpired;

    @Getter
    @Setter
    @Column(name = "account_non_locked", nullable = false)
    private boolean accountNonLocked;

    @Getter
    @Setter
    @Column(name = "credentials_non_expired", nullable = false)
    private boolean credentialsNonExpired;

    @Getter
    @Setter
    @Column(name = "enabled", nullable = false)
    private boolean enabled;

    /**
     * 是否启用两步验证
     */
    @Builder.Default
    @NotNull
    @Getter
    @Setter
    @Column(name = "using_mfa", nullable = false)
    private boolean usingMfa = false;

    /**
     * 两步验证的方式
     */
    @JsonIgnore
    @NotNull
    @Getter
    @Setter
    @Column(name = "mfa_key", nullable = false)
    private String mfaKey;

    @Getter
    @Setter
    @Builder.Default
    @JsonIgnore
    @ManyToMany
    @Fetch(value = FetchMode.JOIN) // join 查询,不用分次查询,提高性能
    @JoinTable(name = "mooc_users_roles",
            joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})

    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
    @BatchSize(size = 20)
    @ToString.Exclude
    private Set<Role> roles = new HashSet<>();


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles.stream().flatMap(role ->
                Stream.concat(Stream.of(new SimpleGrantedAuthority(role.getRoleName()))
                        , role.getPermissions().stream())
        ).collect(Collectors.toList());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
        User user = (User) o;
        return id != null && Objects.equals(id, user.id);
    }

    @Override
    public int hashCode() {
        return getClass().hashCode();
    }
}
